package org.ctstudio.oa.duty.web;

import java.time.LocalDate;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.ctstudio.common.utils.UUIDUtil;
import org.ctstudio.oa.duty.bean.SignQuery;
import org.ctstudio.oa.duty.bean.SignRecord;
import org.ctstudio.oa.duty.bean.Staff;
import org.ctstudio.oa.duty.dao.SignRecordsMapper;
import org.ctstudio.oa.duty.service.DutyCalcService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ValidationUtils;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class SignController extends AbstractController {

  @Autowired
  private SignRecordsMapper mapper;

  @Autowired
  private DutyCalcService dutyCalcService;

  private final static String CLIENTID = "clientId";

  @RequestMapping(value = "/")
  public String index() {
    return "index";
  }

  @RequestMapping(value = "/help.do")
  public String help() {
    return "help";
  }

  @RequestMapping(value = "/sign.do", method = RequestMethod.GET, params = "!uid")
  public String sign(Model model, @CookieValue(value = CLIENTID, required = false) String clientId, HttpServletResponse resp) {
    model.addAttribute("record", new SignRecord());
    // 防止代打卡
    checkClient(clientId, resp);
    return "sign/sign";
  }

  private String checkClient(String clientId, HttpServletResponse resp) {
    if (StringUtils.isEmpty(clientId)) {
      clientId = UUIDUtil.getInstance().randomBase64();
      Cookie cookie = new Cookie(CLIENTID, clientId);
      cookie.setPath("/");
      cookie.setMaxAge(30 * 24 * 60 * 60);
      resp.addCookie(cookie);
    }
    return clientId;
  }

  @RequestMapping(value = "/sign.do", params = "uid")
  public String checkIn(@ModelAttribute("record") SignRecord record, BindingResult result, HttpServletRequest request, Model model,
      @CookieValue(value = CLIENTID, required = false) String clientId, HttpServletResponse resp) {
    ValidationUtils.rejectIfEmptyOrWhitespace(result, "uid", "CANNOTEMPTY");
    Staff staff = null;
    if (!result.hasErrors()) {
      staff = staffMapper.getByStaffId(record.trimUid());
      if (staff == null) {
        result.rejectValue("uid", "NOTEXISTS");
      }
    }

    // 防止代打卡
    clientId = checkClient(clientId, resp);

    if (!result.hasErrors()) {
      record.setIpAddress(request.getRemoteAddr());
      record.setMachine(request.getRemoteHost());
      record.setUserAgent(request.getHeader("user-agent"));
      record.setClientId(clientId);

      SignRecord displacement = mapper.getDisplacement(record);
      if (displacement == null) {
        mapper.add(record);
        record = mapper.get(record.getId());
        dutyCalcService.refreshDuty(record.getSignDate(), record.getUid());
        model.addAttribute("ERRORCODE", "SIGNSUCCEED");
        model.addAttribute("staffName", staff.getName());
      } else {
        model.addAttribute("ERRORCODE", "CANNOTDISPLACEMENT");
        result.rejectValue("uid", null, "");
      }
    }
    return "sign/sign";
  }

  @RequestMapping(value = "/sign/list.do")
  public String signList(@ModelAttribute("query") SignQuery query, Model model) {
    long total = mapper.count(query);
    model.addAttribute("total", total);
    if (total > 0) {
      List<SignRecord> list = mapper.query(query);
      model.addAttribute("map", toMap(list));
      model.addAttribute("staffMap", this.getStaffIdNameMap(list));
    }
    return "sign/list";
  }

  /**
   * 按日期组织打卡记录
   * 
   * @param list
   * @return
   */
  private Map<LocalDate, List<SignRecord>> toMap(List<SignRecord> list) {
    Map<LocalDate, List<SignRecord>> map = list.stream()
        .collect(Collectors.groupingBy(SignRecord::getSignDate, LinkedHashMap::new, Collectors.toList()));
    return map;
  }
}
